package com.spring.demo.webflux.demo.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * 基于注释的webflux端点
 * @author wangzhilong
 * @date 2020/7/7
 */
@RestController
public class DemoController {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @GetMapping(path ="/users/{name}")
    public Mono<String> getName(@PathVariable String name) {
        return Mono.just(name);
    }
    // 阻塞5秒钟
    private String createStr() {
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
        }
        return "some string";
    }

    // 普通的SpringMVC方法
    @GetMapping("/1")
    private String get1() {
        log.info("get1 start");
        String result = createStr();
        log.info("get1 end.");
        return result;
    }

    // WebFlux(返回的是Mono)
    @GetMapping("/2")
    private Mono<String> get2() {
        log.info("get2 start");
        Mono<String> result = Mono.fromSupplier(() -> createStr());
        log.info("get2 end.");
        return result;
    }

    // WebFlux(返回的是Mono)
    @GetMapping("/3")
    private Mono<Integer> get3() {
        log.info("get3 start");
        Mono<String> result = Mono.fromSupplier(() -> createStr());
        final Mono<Integer> result2 = Mono.just(new String[]{"1", "2"})
                .flatMap(v -> Mono.just(v.length))
                .flatMap(v -> Mono.just(v * v));
        log.info("get3 end.");
        return result2;
    }

    /**
     * WebFlux还支持服务器推送(SSE - >Server Send Event)
     * Flux : 返回0-n个元素
     * 注：需要指定MediaType
     * @return
     */
    @GetMapping(value = "/3", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    private Flux<String> flux() {
        Flux<String> result = Flux
                .fromStream(IntStream.range(1, 5).mapToObj(i -> {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                    }
                    return "flux data--" + i;
                }));
        return result;
    }

    private Object getPerson(){
        return "person one";
    }

    /**
     * 得到一个包装 数据序列 -> 包含特征  -> 容器 拿到这个序列 -> 执行序列里的方法
     * @return
     */
    @GetMapping("/mono")
    private Mono<Object> mono() {
        System.out.println("---1----线程："+Thread.currentThread().getName());

        //定义一个数据流(数据序列)
        final Mono<Object> mono = Mono.create(monoSink -> {
                    //定义数据序列的特征(来源)
                    System.out.println("create:" + Thread.currentThread().getName());
                    monoSink.success(getPerson());
                 })
                //订阅
                .doOnSubscribe(sub -> {
                    System.out.println("doOnSubscribe:" + Thread.currentThread().getName());
                })
                //得到数据
                .doOnNext(data -> {
                    System.out.println("doOnNext data:" + data + "," + Thread.currentThread().getName());
                })
                //整体完成
                .doOnSuccess(s -> {
                    System.out.println("doOnSuccess:" + s + "," + Thread.currentThread().getName());
                }).
                doOnError(error -> {
                    System.out.println("doOnError:" + error.getMessage() + "," + Thread.currentThread().getName());
                });
        System.out.println("---2----");
        //看起来像是异步，实质上，阻塞的过程是在容器内部
        //返回一个数据序列，返回到容器中，由容器进行订阅处理后返回给浏览器
        return mono;
    }




}
